<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\Plugin\DrainageLink\Action\Operation;

use EasyWeChat\Factory;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use MoChat\Framework\Action\AbstractAction;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;
use MoChat\Framework\Request\ValidateSceneTrait;
use MoChat\Plugin\DrainageLink\Contract\DrainageLinkClickContract;
use Psr\SimpleCache\CacheInterface;

/**
 * 引流链接H5- 获取二维码.
 *
 * Class ContactData.
 * @Controller
 */
class GetScheme extends AbstractAction
{
    use ValidateSceneTrait;

    public const CACHE_KEY = 'DRAINAGE_LINK_SCHEME:%d';

    /**
     * @Inject
     * @var DrainageLinkClickContract
     */
    protected $drainageLinkClickService;

    /**
     * @Inject
     * @var StdoutLoggerInterface
     */
    private $logger;

    /**
     * @Inject
     * @var CacheInterface
     */
    private $cache;

    /**
     * @RequestMapping(path="/operation/drainageLink/getScheme", methods="get")
     */
    public function handle(): array
    {
        // 接收参数
        $params = [
            'id' => (int) $this->request->input('id'),
        ];
        // 参数验证
        $this->validated($params);
        // 点击统计
        $this->createDrainageLinkClick($params);
        // 查看缓存
        $openLink = $this->cache->get(sprintf(self::CACHE_KEY, $params['id']));
        if ($openLink) {
            return [
                'openLink' => $openLink,
            ];
        }

        // 查询数据
        $weChatMiniProgramConfig = config('framework.wechat_mini_program');

        if (empty($weChatMiniProgramConfig['app_id']) || empty($weChatMiniProgramConfig['secret'])) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '小程序配置错误');
        }

        $miniProgram = Factory::miniProgram($weChatMiniProgramConfig);
        /** @var \EasyWeChat\MiniProgram\Application $miniProgram */
        $miniProgram = rebind_app($miniProgram, $this->request);
        $data = [
            'jump_wxa' => [
                'path' => $weChatMiniProgramConfig['path'],
                'query' => 'id=' . $params['id'],
                'env_version' => $weChatMiniProgramConfig['version'],
            ],
            'is_expire' => true,
            'expire_type' => 1,
            'expire_interval' => 180,
        ];
        $result = $miniProgram->url_scheme->generate($data);

        if ($result['errcode'] !== 0) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, $result['errmsg']);
        }

        $this->cache->set(sprintf(self::CACHE_KEY, $params['id']), $result['openlink'], 86400 * 179);

        return [
            'openLink' => $result['openlink'],
        ];
    }

    /**
     * 验证规则.
     *
     * @return array 响应数据
     */
    protected function rules(): array
    {
        return [
            'id' => 'required | integer | min:0 | bail',
        ];
    }

    /**
     * 验证错误提示.
     * @return array 响应数据
     */
    protected function messages(): array
    {
        return [
            'id.required' => '链接ID 必填',
            'id.integer' => '链接ID 必需为整数',
            'id.min' => '链接ID 不可小于1',
        ];
    }

    /**
     * 点击统计
     */
    private function createDrainageLinkClick(array $params): array
    {
        # # 数据操作
        Db::beginTransaction();
        try {
            # # 创建点击记录
            $data = [
                'link_id' => $params['id'],
                'created_at' => date('Y-m-d H:i:s'),
            ];
            $this->drainageLinkClickService->createDrainageLinkClick($data);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            $this->logger->error(sprintf('%s [%s] %s', '链接点击统计失败', date('Y-m-d H:i:s'), $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
        }
        return [];
    }
}
